/************************ (C) COPYLEFT 2018 Merafour *************************

* File Name          : Curve.h
* Author             : Merafour
* Last Modified Date : 01/10/2019
* Description        : 数学曲线.
********************************************************************************
* https://merafour.blog.163.com
* merafour@163.com
* https://github.com/merafour
******************************************************************************/
#ifndef _CURVE_H_
#define _CURVE_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdint.h>
#include "hsv.h"

/************************************************** 数学曲线 ***************************************************************************/
extern const float sin_table[361];   // 正弦函数值查表
extern const float cos_table[361];   // 余弦函数值查表
extern const uint8_t sin_rgb_blend[361];   // RGB通道正弦函数分布值查表
extern const uint8_t cos_rgb_blend[361];   // RGB通道余弦函数分布值查表
// RGB以120°相位差混色
extern uint32_t angle_rgb(uint16_t const angle);   // RGB正弦曲线混合, 计算好的 RGB通道值, 节约算力
// RGB以180°两两混色,rg[0-360], gb[360-720], br[720-1080]
extern uint32_t angle_rg_gb_br(uint16_t const angle);
extern uint32_t angle_256(uint16_t const angle);

#define  ANGLE_HSV_PRE       2
#define  ANGLE_HSV_CIRCUM   (360<<ANGLE_HSV_PRE)
static inline uint16_t angle_hsv_up(uint16_t angle, const uint16_t degree)
{
	const uint16_t circum = ANGLE_HSV_CIRCUM;   // 放大四倍,这样调整1°就变为 0.25°
	angle += degree;
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle>=circum) angle = angle - circum;
		else break;
	}
	return angle;
}
static inline uint16_t angle_hsv_down(const uint16_t Angle, const uint16_t degree)
{
	const uint16_t circum = ANGLE_HSV_CIRCUM;   // 放大四倍,这样调整1°就变为 0.25°
	int32_t angle = Angle;
	angle -= degree;
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle>=circum) angle = angle - circum;
		else break;
	}
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle<0) angle = angle + circum;
		else break;
	}
	return angle;
}
static inline uint16_t hsv_angle(const uint16_t angle)
{
	return (angle>>ANGLE_HSV_PRE);
}
static inline uint8_t angle_hsv_speed(const uint8_t speed)
{
	return (speed+4);
}
static inline uint32_t angle_hsv_rgb(const uint16_t angle)
{
    //           hue, saturation, value
    hsv_t hsv = {0, 255, 255};
	//hsv.value = 255;
	hsv.hue = angle>>ANGLE_HSV_PRE;
	//hsv.saturation = 255;
	return hsv2rgb(&hsv);
}
	
static inline uint16_t angle_cnt_up(uint16_t angle, const uint16_t degree)
{
	//if(angle>360) angle=angle%360;   // 安全检查
	angle += degree;
	//if(angle>=360) angle = angle - 360;
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle>=360) angle = angle - 360;
		else break;
	}
	return angle;
}
static inline uint16_t angle_cnt_down(const uint16_t Angle, const uint16_t degree)
{
#if 0
	if(angle>360) angle=angle%360;   // 安全检查
	if(angle>=degree) angle -= degree;
	else angle = angle + 360 - degree;
	if(angle>=360) angle = angle - 360;
#else
	int32_t angle = Angle;
	angle -= degree;
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle>=360) angle = angle - 360;
		else break;
	}
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle<0) angle = angle + 360;
		else break;
	}
#endif
	return angle;
}
static inline uint16_t angle_1080_up(uint16_t angle, const uint16_t degree)
{
	//if(angle>1080) angle=angle%1080;   // 安全检查
	angle += degree;
	//if(angle>=1080) angle = angle - 1080;
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle>=1080) angle = angle - 1080;
		else break;
	}
	return angle;
}
static inline uint16_t angle_1080_down(const uint16_t Angle, const uint16_t degree)
{
#if 0
	if(angle>1080) angle=angle%1080;   // 安全检查
	if(angle>=degree) angle -= degree;
	else angle = angle + 1080 - degree;
	if(angle>=1080) angle = angle - 1080;
#else
	int32_t angle = Angle;
	angle -= degree;
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle>=1080) angle = angle - 1080;
		else break;
	}
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle<0) angle = angle + 1080;
		else break;
	}
#endif
	return angle;
}

static inline uint16_t angle_256_up(uint16_t angle, const uint16_t degree)
{
	angle += degree;
	for(int i=0; i<100; i++)   // 安全检查
	{
		// 256*6
		if(angle>=1536) angle = angle - 1536;
		else break;
	}
	return angle;
}
static inline uint16_t angle_256_down(const uint16_t Angle, const uint16_t degree)
{
	int32_t angle = Angle;
	angle -= degree;
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle>=1536) angle = angle - 1536;
		else break;
	}
	for(int i=0; i<100; i++)   // 安全检查
	{
		if(angle<0) angle = angle + 1536;
		else break;
	}
	return angle;
}

	
/************************************************** 3D engine ***************************************************************************/
extern void ArotateX(const uint16_t angle, const float* const point, float* const output);// rotate matrix for X
extern void ArotateY(const uint16_t angle, const float* const point, float* const output);// rotate matrix for Y
extern void ArotateZ(const uint16_t angle, const float* const point, float* const output);// rotate matrix for Z
extern void projectOnXY(const float* const point, float* const output, const float zFactor);

#ifdef __cplusplus
}
#endif

#endif /* _CURVE_H_ */

